package com.example.springstudy.base.aspect;

import cn.hutool.json.JSONUtil;
import com.example.springstudy.base.Result;
import com.example.springstudy.base.annotation.SaveLog;
import com.example.springstudy.entity.LogEntity;
import com.example.springstudy.entity.LogErr;
import com.example.springstudy.mapper.LogErrMapper;
import com.example.springstudy.service.LogService;
import com.example.springstudy.utils.DateUtils;
import com.example.springstudy.utils.RequestUtils;
import com.example.springstudy.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
@Order(10)
public class SaveLogAspect {

    @Autowired
    LogService logService;
    @Autowired
    LogErrMapper logErrMapper;

    @Pointcut("@annotation(com.example.springstudy.base.annotation.SaveLog)")
    public void logPointCut() {}

    @Pointcut("execution(* com.example.springstudy.controller.*.*(..))")
    public void throwingPointCut(){

    }

    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("Before execute method: {}", joinPoint);
        MethodSignature method = (MethodSignature) joinPoint.getSignature();
        if(method.getName().equals("logout")){
            LogEntity entity = new LogEntity();
            String ip = RequestUtils.getIp();
            entity.setIp(ip);
            SaveLog saveLog = method.getMethod().getAnnotation(SaveLog.class);
            if(saveLog != null){
                String value = saveLog.value();
                entity.setOperation(value);
            }
            entity.setMethod(method.getName());
            entity.setParams(JSONUtil.toJsonStr(joinPoint.getArgs()));
            entity.setUserId(SecurityUtils.getUserId());
            entity.setUserName(SecurityUtils.getUsername());
            entity.setCreateTime(DateUtils.defaultDate());
            logService.saveLog(entity);
        }
    }

    @AfterReturning(pointcut = "logPointCut()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        log.info("After return execute method: {}, result: {}", joinPoint.getSignature().getName(), result);
        MethodSignature method = (MethodSignature) joinPoint.getSignature();
        if(method.getName().equals("logout")) return;
        SaveLog saveLog = method.getMethod().getAnnotation(SaveLog.class);
        LogEntity entity = new LogEntity();
        if(saveLog != null){
            String value = saveLog.value();
            entity.setOperation(value);
        }
        String ip = RequestUtils.getIp();
        entity.setIp(ip);
        entity.setMethod(method.getName());
        Result<?> res = (Result<?>)result;
        entity.setResult("code:"+res.getCode()+", msg:"+res.getMsg());
        entity.setParams(JSONUtil.toJsonStr(joinPoint.getArgs()));
        entity.setUserId(SecurityUtils.getUserId());
        entity.setUserName(SecurityUtils.getUsername());
        entity.setCreateTime(DateUtils.defaultDate());
        logService.saveLog(entity);
    }

    @AfterThrowing(pointcut = "throwingPointCut()", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
        log.info("After throw execute method: {},  exception: {}", joinPoint.getSignature().getName(), ex.getMessage());
        MethodSignature method = (MethodSignature) joinPoint.getSignature();
        LogErr logErr = new LogErr();
        logErr.setMethod(method.getName());
        logErr.setParams(JSONUtil.toJsonStr(joinPoint.getArgs()));
        logErr.setUserId(SecurityUtils.getUserId());
        logErr.setCreateTime(DateUtils.defaultDate());
        logErr.setError(ex.getMessage());
        logErrMapper.saveLogErr(logErr);
    }
}
